package liquidfs.ui.net;

import java.io.*;
import java.net.*;
import java.util.logging.*;
import utility.*;

import liquidfs.*;
import liquidfs.core.OperationProcessor;

public class MessageServer implements Runnable {

	private static Logger log = Logger.getLogger("liquidfs.ui.net.MessageServer");
	
	private Application app;
	private OperationProcessor processor;
	private Context context;
	
	private ServerSocket binarySocket;
	private ServerSocket xmlSocket;
	
	public MessageServer (Application app) {
		this.app = app;
		this.processor = app.getOperationProcessor();
		this.context = app.getContext();
	}
	
	public MessageClient accept () throws IOException, UserCheckedException
	{
		if (binarySocket == null || xmlSocket == null)
			initialize();
		
		Socket xmlClient = xmlSocket.accept();
		Socket binClient = binarySocket.accept();
		
		return new MessageClient(app, xmlClient, binClient);
	}
	
	private boolean initialize () {
		
		try
		{
			binarySocket = new ServerSocket(app.getConfiguration().getDataPort());
		}
		catch (IOException e)
		{
			log.log(Level.SEVERE, "Unable to create binary server socket on port " + app.getConfiguration().getDataPort() + ";\n" + e.getLocalizedMessage());
			return false;
		}
		
		try
		{
			xmlSocket = new ServerSocket(app.getConfiguration().getMessagePort());
		}
		catch (IOException e)
		{
			log.log(Level.SEVERE, "Unable to create xml server socket on port " + app.getConfiguration().getMessagePort() + ";\n" + e.getLocalizedMessage());
			return false;
		}
		
		return true;
		
	}

	@Override
	public void run() {
		
		// Attempt to start the server
		boolean success = initialize ();
		
		// Create a thread pool
		ParameterizedExecutor executor = new ParameterizedCachedThreadPool();
		
		// End the thread on failure
		if (!success)
			return;
		
		while (true) {
			
			MessageClient client = null;
			
			// Allow a client to connect
			try	{
				client = this.accept();
			}
			catch (UserCheckedException e) {
				log.log(Level.WARNING, e.getLocalizedMessage());
				continue;
			}
			catch (IOException e) {
				log.log(Level.WARNING, "Failed to accept an incomming connection;\n" + e.getLocalizedMessage());
				continue;
			}
			
			// Create a thread to deal with the client's request
			executor.execute(this.processor, client);
		}
		
	}

}
